package com.tc.travel.submitter.executor;

import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.google.gson.Gson;
import com.tc.travel.submitter.pojo.AgentInfo;
import com.tc.travel.submitter.pojo.VisaAddUpdateDto;
import com.tc.travel.util.Consts;
import com.tc.travel.util.DateUtil;
import com.tc.travel.util.HtmlUtil;
import com.tc.travel.util.HttpClientUtil;
import com.tc.travel.util.PropertyUtil;
import com.tc.travel.util.SleepUtil;
import com.tc.travel.util.StringUtil;
import com.tc.travel.util.exception.ComRuntimeException;

@Component
public class VisaAdd {
	private static Logger log = Logger.getLogger(VisaAdd.class);

	public String execute(VisaAddUpdateDto visaSubmitDto, String cookie) {
		log.info("VisaAdd.execute...");

		String submitVisaPageKey = openSubmitVisaPage(cookie);
		log.info("submitVisaPageKey:" + submitVisaPageKey);

		SleepUtil.sleepRandom(1, 2);
		AgentInfo agentInfo = getAgentInfo(visaSubmitDto.getChinaAgentCode(), cookie);
		log.info("agentInfo:" + agentInfo);

		SleepUtil.sleepRandom(3, 8);
		String confirmSubmitVisaPageKey = submitVisa(visaSubmitDto, agentInfo, submitVisaPageKey, cookie);
		log.info("confirmSubmitVisaPageKey:" + confirmSubmitVisaPageKey);

		SleepUtil.sleepRandom(1, 3);
		String destVisaId = confirmSubmitVisa(confirmSubmitVisaPageKey, cookie);
		log.info("destVisaId:" + destVisaId);
		return destVisaId;
	}

	public String openSubmitVisaPage(String cookie) {
		String url = PropertyUtil.destUrlVisaEdit;

		Map<String, String> params = new HashMap<String, String>();
		// params.put("mode", "add");

		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Cookie", cookie);
		headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		headers.put("Accept-Encoding", "gzip, deflate, sdch, br");
		headers.put("Accept-Language", "en-US,en;q=0.8,ja;q=0.6");
		headers.put("Connection", "keep-alive");
		headers.put("Host", "churenkyosystem.com");
		headers.put("Referer", "https://churenkyosystem.com/member/top.php");
		headers.put("Upgrade-Insecure-Requests", "1");
		headers.put("User-Agent", Consts.USER_AGENT);

		String html = HttpClientUtil.doGet(url, params, headers);
		assertSubmitVisaPage(html);

		return HtmlUtil.getPageKey(html);
	}

	private void assertSubmitVisaPage(String html) {
		if (StringUtil.isEmpty(html)) {
			throw new ComRuntimeException("openSubmitVisaPage error; returned html is null.");
		}

		if (html.indexOf("身元保証書新規発行") < 0 || html.indexOf("入力画面") < 0 || html.indexOf("査証種別") < 0) {
			if (html.indexOf("<form action=\"login.php\" method=\"post\">") >= 0) {
				throw new ComRuntimeException("cookie expired, please assign new cookie.");
			} else {
				throw new ComRuntimeException("openSubmitVisaPage error; html content error.");
			}
		}

		String pageKey = HtmlUtil.getPageKey(html);
		if (StringUtil.isEmpty(pageKey)) {
			throw new ComRuntimeException("openSubmitVisaPage error; no page key found.");
		}
	}

	private AgentInfo getAgentInfo(String chinaAgentCode, String cookie) {
		log.info("chinaAgentCode: " + chinaAgentCode);

		String url = PropertyUtil.destUrlGetChinaAgent;
		Map<String, String> params = new HashMap<String, String>();
		params.put("CHINA_AGENT_CODE", chinaAgentCode);

		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Cookie", cookie);
		headers.put("Accept", "application/json, text/javascript, */*; q=0.01");
		headers.put("Accept-Encoding", "gzip, deflate, br");
		headers.put("Accept-Language", "en-US,en;q=0.8,ja;q=0.6");
		headers.put("Connection", "keep-alive");
		// headers.put("Content-Length","29");
		headers.put("Content-Type", "application/x-www-form-urlencoded");
		headers.put("Host", "churenkyosystem.com");
		headers.put("Origin", "https://churenkyosystem.com");
		headers.put("Referer", "https://churenkyosystem.com/member/identity_edit.php?mode=add");
		headers.put("User-Agent", Consts.USER_AGENT);
		headers.put("X-Requested-With", "XMLHttpRequest");

		String jsonStr = HttpClientUtil.doPost(url, params, headers);
		asserAgentInfo(jsonStr, chinaAgentCode);

		AgentInfo agentInfo = new Gson().fromJson(jsonStr, AgentInfo.class);
		return agentInfo;
	}

	private void asserAgentInfo(String jsonStr, String expectedChinaAgentCode) {
		if (StringUtil.isEmpty(jsonStr)) {
			throw new ComRuntimeException("getAgentInfo error; returned jsonStr is null.");
		}

		try {
			AgentInfo agentInfo = new Gson().fromJson(jsonStr, AgentInfo.class);
			if (agentInfo == null) {
				throw new ComRuntimeException("getAgentInfo error; converted AgentInfo is null.");
			} else {
				if (!expectedChinaAgentCode.equals(agentInfo.getCOMPANY_CODE())) {
					throw new ComRuntimeException("getAgentInfo error; converted AgentInfo is illegal, agent code is not expected.");
				}
			}
		} catch (Exception e) {
			throw new ComRuntimeException("getAgentInfo error; connot convert json str to AgentInfo Object.", e);
		}
	}

	public String submitVisa(VisaAddUpdateDto visaSubmitDto, AgentInfo agentInfo, String pageKey, String cookie) {
		String url = PropertyUtil.destUrlVisaEdit;
		Map<String, String> params = new HashMap<String, String>();
		// agent info
		params.put("CHINA_AGENT_ID", agentInfo.getCHINA_AGENT_ID());
		params.put("CHINA_AGENT_CODE", agentInfo.getCOMPANY_CODE());
		params.put("viewAgent_company", agentInfo.getCOMPANY_NAME());
		params.put("viewAgent_diplomat", agentInfo.getDIPLOMAT_NAME());
		// visa info
		params.put("APPLICANT_NAME", visaSubmitDto.getApplicantName());
		params.put("APPLICANT_PINYIN", visaSubmitDto.getApplicantPinyin());
		params.put("NUMBER_OF_TOURISTS", visaSubmitDto.getOtherPersonNum() + "");
		params.put("ARRIVAL_DATE", DateUtil.formatToDestStyle(visaSubmitDto.getArrivalDate()));
		params.put("DEPARTURE_DATE", DateUtil.formatToDestStyle(visaSubmitDto.getDepartureDate()));

		// VISA_TYPE, VISA_TYPE_1, VISA_TYPE_2
		params.put("VISA_TYPE", visaSubmitDto.getVisaType());
		params.put("VISA_TYPE_1", visaSubmitDto.getVisaType1());
		params.put("VISA_TYPE_2", visaSubmitDto.getVisaType2());

		// VISA_STAY_PREF_47, 2, 3, 4, 5, 6, 7
		if (!StringUtil.isEmpty(visaSubmitDto.getVisaStayPrefList())) {
			String[] visaStayPrefArr = visaSubmitDto.getVisaStayPrefList().split(",");
			for (String visaStayPref : visaStayPrefArr) {
				if (!StringUtil.isEmpty(visaStayPref)) {
					params.put("VISA_STAY_PREF_" + visaStayPref, visaStayPref);
				}
			}
		}

		// VISA_VISIT_TYPE
		params.put("VISA_VISIT_TYPE", visaSubmitDto.getVisaVistType());

		// VISA_VISIT_PREF_3, 4, 7
		if (!StringUtil.isEmpty(visaSubmitDto.getVisaVistPrefList())) {
			String[] visaVistPrefArr = visaSubmitDto.getVisaVistPrefList().split(",");
			for (String visaVistPref : visaVistPrefArr) {
				if (!StringUtil.isEmpty(visaVistPref)) {
					params.put("VISA_VISIT_PREF_" + visaVistPref, visaVistPref);
				}
			}
		}

		// page key
		params.put("_PAGE_KEY", pageKey);
		params.put("BTN_CHECK_x", "確 認");

		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Cookie", cookie);
		headers.put("User-Agent", Consts.USER_AGENT);
		headers.put("Accept-Language", "en-US,en;q=0.8,ja;q=0.6");
		headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		headers.put("Cache-Control", "max-age=0");
		headers.put("Origin", "https://churenkyosystem.com");
		headers.put("Upgrade-Insecure-Requests", "1");
		headers.put("Referer", "https://churenkyosystem.com/member/identity_edit.php?mode=add");
		headers.put("Accept-Encoding", "sdch");

		String html = HttpClientUtil.doPost(url, params, headers);
		assertConfirmSubmitVisaPage(html);

		return HtmlUtil.getPageKey(html);
	}

	private void assertConfirmSubmitVisaPage(String html) {
		if (StringUtil.isEmpty(html)) {
			throw new ComRuntimeException("submitVisa error; returned html is null.");
		}

		if (html.indexOf("身元保証書発行内容") < 0 || html.indexOf("確認画面") < 0 || html.indexOf("査証種別") < 0) {
			throw new ComRuntimeException("submitVisa error; html content error.");
		}

		String pageKey = HtmlUtil.getPageKey(html);
		if (StringUtil.isEmpty(pageKey)) {
			throw new ComRuntimeException("submitVisa error; no page key found.");
		}
	}

	public String confirmSubmitVisa(String pageKey, String cookie) {
		String url = PropertyUtil.destUrlVisaEdit;
		Map<String, String> params = new HashMap<String, String>();
		params.put("_PAGE_KEY", pageKey);
		params.put("MAIL_STATUS", "0");
		params.put("BTN_CHECK_SUBMIT_x", "登 録");

		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Cookie", cookie);
		headers.put("User-Agent", Consts.USER_AGENT);
		headers.put("Accept-Language", "en-US,en;q=0.8,ja;q=0.6");

		String html = HttpClientUtil.doPost(url, params, headers);
		assertConfirmSubmitVisaResultPage(html);
		return HtmlUtil.getDestVisaId(html);
	}

	private void assertConfirmSubmitVisaResultPage(String html) {
		if (StringUtil.isEmpty(html)) {
			throw new ComRuntimeException("confirmSubmitVisa error; returned html is null.");
		}

		if (html.indexOf("身元保証書発行") < 0 || html.indexOf("完了画面") < 0 || html.indexOf("受付番号") < 0) {
			throw new ComRuntimeException("confirmSubmitVisa error; html content error.");
		}

		String destVisaId = HtmlUtil.getDestVisaId(html);
		if (StringUtil.isEmpty(destVisaId)) {
			throw new ComRuntimeException("confirmSubmitVisa error; no dest visa id found.");
		}
	}

}
